package fun.werfamily.wf.order.core.domain.service.impl;

import fun.werfamily.wf.base.dto.LoginUserContext;
import fun.werfamily.wf.base.vo.PageInfo;
import fun.werfamily.wf.order.core.domain.constant.RedisConstant;
import fun.werfamily.wf.order.core.domain.constant.RedisTimeoutConstants;
import fun.werfamily.wf.order.core.domain.dto.req.*;
import fun.werfamily.wf.order.core.domain.dto.req.goods.GoodsLineDTO;
import fun.werfamily.wf.order.core.domain.dto.req.goods.GoodsSkuDTO;
import fun.werfamily.wf.order.core.domain.dto.result.*;
import fun.werfamily.wf.order.core.domain.dto.result.user.UserAddressDTO;
import fun.werfamily.wf.order.core.domain.enums.OrderOriginEnum;
import fun.werfamily.wf.order.core.domain.enums.OrderStatusEnum;
import fun.werfamily.wf.order.core.domain.enums.ResponseCodeEnum;
import fun.werfamily.wf.order.core.domain.exception.OrderCoreException;
import fun.werfamily.wf.order.core.domain.remote.dto.PaySuccessRespDTO;
import fun.werfamily.wf.order.core.domain.remote.facade.GoodsServiceFacade;
import fun.werfamily.wf.order.core.domain.remote.facade.PaymentServiceFacade;
import fun.werfamily.wf.order.core.domain.remote.facade.UserServiceFacade;
import fun.werfamily.wf.order.core.domain.service.OrderGoodsCartService;
import fun.werfamily.wf.order.core.domain.service.OrderService;
import fun.werfamily.wf.order.core.domain.util.OrderNoGenUtil;
import fun.werfamily.wf.order.core.domain.util.RedisUtil;
import fun.werfamily.wf.order.core.infrastructure.dataobject.OrderDO;
import fun.werfamily.wf.order.core.infrastructure.dataobject.OrderGoodsDO;
import fun.werfamily.wf.order.core.infrastructure.mapper.OrderGoodsMapper;
import fun.werfamily.wf.order.core.infrastructure.mapper.OrderMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: Mr.WenMing Zhang
 * @Date: 2022-08-28 12:23
 * @Description:
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Resource
    private UserServiceFacade userServiceFacade;

    @Resource
    private GoodsServiceFacade goodsServiceFacade;

    @Resource
    private PaymentServiceFacade paymentServiceFacade;

    @Resource
    private OrderGoodsCartService cartService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private OrderGoodsMapper orderGoodsMapper;

    private final String CHANNEL_CODE = "ZY";

    /**
     * 确认订单
     * 1.获取商品详情 计算价格
     * 2.拼装收货人信息
     * 3.查询用户信息
     * 4.存入缓存
     *
     * @param orderConfirmReqDTO
     * @return
     */
    @Override
    public OrderDTO orderConfirm(OrderConfirmReqDTO orderConfirmReqDTO) {
        String userCode = LoginUserContext.getUserCode();
        initOrderDTO(orderConfirmReqDTO);
        // 计算订单金额
        OrderDTO orderDTO = calculateOrderAmount(orderConfirmReqDTO.getGoodsList());
        String orderNo = OrderNoGenUtil.getOrderNo();
        orderDTO.setPreOrderNo(orderNo);
        UserAddressDTO addressDTO = null;
        if (orderConfirmReqDTO.getAddressId() != null) {
            addressDTO = userServiceFacade.getAddressById(orderConfirmReqDTO.getAddressId());
        }
        // 获取默认收货地址
        if (orderConfirmReqDTO.getAddressId() == null) {
            addressDTO = userServiceFacade.getDefaultAddr(userCode);
        }

        if (null != addressDTO) {
            orderDTO.setAddressId(addressDTO.getId());
            orderDTO.setConsignee(addressDTO.getConsignee());
            orderDTO.setMobile(addressDTO.getMobile());
            orderDTO.setProvinceName(addressDTO.getProvinceName());
            orderDTO.setCityName(addressDTO.getCityName());
            orderDTO.setAreaName(addressDTO.getAreaName());
            orderDTO.setDetailAddress(addressDTO.getAddress());
            orderDTO.setAddressTag(addressDTO.getTag());
        }
        orderDTO.setUserCode(userCode);
        orderDTO.setUserName(LoginUserContext.getUserName());
        orderDTO.setRemark(orderConfirmReqDTO.getRemark());
        orderDTO.setOrigin(orderConfirmReqDTO.getOrigin());
        redisUtil.saveObject(RedisConstant.PRE_ORDER_PREFIX + orderNo, orderDTO, RedisTimeoutConstants.CACHE_HOLD_TIME_5M);
        return orderDTO;
    }

    /**
     * 计算订单金额
     *
     * @param goodsLineDTOS
     * @return
     */
    public OrderDTO calculateOrderAmount(List<GoodsLineDTO> goodsLineDTOS) {
        OrderDTO orderDTO = new OrderDTO();
        if (CollectionUtils.isEmpty(goodsLineDTOS)) {
            return orderDTO;
        }
        List<String> skuCodes = goodsLineDTOS.stream().map(GoodsLineDTO::getSkuCode).collect(Collectors.toList());
        Map<String, Integer> skuNumMap = goodsLineDTOS.stream().collect(Collectors.toMap(GoodsLineDTO::getSkuCode, GoodsLineDTO::getQuantity));
        // 商品信息
        List<GoodsSkuDTO> goodsSkuDTOS = goodsServiceFacade.goodsSkuDetail(skuCodes);
        BigDecimal goodsAmount = BigDecimal.ZERO;
        int goodsNum = 0;
        if (!CollectionUtils.isEmpty(goodsSkuDTOS)) {
            List<OrderGoodsDTO> orderGoodsDTOList = new ArrayList<>();
            for (GoodsSkuDTO goodsSkuDTO : goodsSkuDTOS) {
                Integer num = skuNumMap.get(goodsSkuDTO.getSkuCode());
                BigDecimal tempAmount = goodsSkuDTO.getSalesPrice().multiply(new BigDecimal(num.toString()));
                goodsAmount = goodsAmount.add(tempAmount);
                OrderGoodsDTO orderGoodsDTO = new OrderGoodsDTO();
                orderGoodsDTO.setGoodsName(goodsSkuDTO.getSkuName());
                orderGoodsDTO.setGoodsImage(goodsSkuDTO.getShortImage());
                orderGoodsDTO.setSpuCode(goodsSkuDTO.getSpuCode());
                orderGoodsDTO.setSkuCode(goodsSkuDTO.getSkuCode());
                orderGoodsDTO.setUnit(goodsSkuDTO.getUnit());
                orderGoodsDTO.setGoodsSalesPrice(goodsSkuDTO.getSalesPrice());
                orderGoodsDTO.setGoodsCostPrice(goodsSkuDTO.getCostPrice());
                orderGoodsDTO.setGoodsNum(num);
                orderGoodsDTOList.add(orderGoodsDTO);
                goodsNum = goodsNum + num;
            }
            orderDTO.setGoodsAmount(goodsAmount);
            orderDTO.setOrderAmount(goodsAmount);
            orderDTO.setGoodsNum(goodsNum);
            orderDTO.setOrderGoodsDTOList(orderGoodsDTOList);
            orderDTO.setOrderDiscountAmount(BigDecimal.ZERO);
        }
        return orderDTO;
    }

    /**
     * 提交订单
     * 1.参数校验
     * 2.订单优惠信息
     * 3.计算订单金额
     * 4.锁定库存
     * 5.生成订单
     *
     * @param orderSubmitReqDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDTO orderSubmit(OrderSubmitReqDTO orderSubmitReqDTO) {
        // 参数校验
        checkParam(orderSubmitReqDTO);
        OrderDTO orderDTO = (OrderDTO) redisUtil.getObject(RedisConstant.PRE_ORDER_PREFIX + orderSubmitReqDTO.getPreOrderNo(), OrderDTO.class);
        if (orderDTO == null){
            // 停留时间过长请重新下单
            throw new OrderCoreException(ResponseCodeEnum.WAIT_TOO_LONG);
        }
        List<GoodsLineDTO> goodsLineDTOS = new ArrayList<>();
        List<String> skuCodes = new ArrayList<>();
        for (OrderGoodsDTO orderGoodsDTO : orderDTO.getOrderGoodsDTOList()) {
            GoodsLineDTO goodsLineDTO = new GoodsLineDTO();
            goodsLineDTO.setSkuCode(orderGoodsDTO.getSkuCode());
            goodsLineDTO.setQuantity(orderGoodsDTO.getGoodsNum());
            goodsLineDTOS.add(goodsLineDTO);
            skuCodes.add(orderGoodsDTO.getSkuCode());
        }
        OrderDTO orderDTONew = calculateOrderAmount(goodsLineDTOS);
        if (orderDTO.getOrderAmount().compareTo(orderDTONew.getOrderAmount()) != 0){
            // 订单金额发生变化 请重新下单
            throw new OrderCoreException(ResponseCodeEnum.ORDER_AMOUNT_CHANGED);
        }
        // TODO 锁定库存

        // 生成主订单
        String orderNo = OrderNoGenUtil.getOrderNo();
        orderDTO.setOrderNo(orderNo);
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderDTO, orderDO);
        orderDO.setOrderNo(orderNo);
        orderDO.setCreateBy(String.valueOf(orderDTO.getUserCode()));
        orderDO.setUpdateBy(String.valueOf(orderDTO.getUserCode()));
        orderDO.setUserMobile(orderDTO.getUserName());
        orderDO.setMobile(orderDTO.getMobile());
        orderDO.setChannelCode(CHANNEL_CODE);
        orderDO.setOrderStatus(OrderStatusEnum.WAIT_PAY.getOrderStatus());
        orderDO.setOrderDiscountAmount(orderDTO.getOrderDiscountAmount());
        orderMapper.insertSelective(orderDO);
        // 生成商品订单
        List<OrderGoodsDTO> orderGoodsDTOList = orderDTO.getOrderGoodsDTOList();
        List<OrderGoodsDO> orderGoodsDOS = new ArrayList<>(orderGoodsDTOList.size());
        for (OrderGoodsDTO orderGoodsDTO : orderGoodsDTOList) {
            // 生成商品订单号
            String orderGoodsNo = OrderNoGenUtil.getOrderNo();
            OrderGoodsDO orderGoodsDO = OrderGoodsDO.builder()
                    .orderId(orderDO.getId())
                    .orderNo(orderNo)
                    .orderGoodsNo(orderGoodsNo)
                    .spuCode(orderGoodsDTO.getSpuCode())
                    .skuCode(orderGoodsDTO.getSkuCode())
                    .orderGoodsStatus(OrderStatusEnum.WAIT_PAY.getOrderStatus())
                    .goodsImage(orderGoodsDTO.getGoodsImage())
                    .goodsNum(orderGoodsDTO.getGoodsNum())
                    .saleUnit(orderGoodsDTO.getUnit())
                    .goodsName(orderGoodsDTO.getGoodsName())
                    .goodsSalesPrice(orderGoodsDTO.getGoodsSalesPrice())
                    .goodsCostPrice(orderGoodsDTO.getGoodsCostPrice())
                    .createBy(orderDO.getUserCode())
                    .updateBy(orderDO.getUserCode())
                    .build();
            orderGoodsMapper.insertSelective(orderGoodsDO);
            orderGoodsDOS.add(orderGoodsDO);
        }
        // 删除购物车商品
        if (OrderOriginEnum.GOODS_CART.getOrigin().equals(orderDTO.getOrigin())) {
            cartService.removeGoodsCartItem(skuCodes);
        }
        return orderDTO;
    }

    @Override
    public OrderDTO orderCreate(OrderConfirmReqDTO orderConfirmReqDTO) {
        // 确认订单
        OrderDTO orderDTO = orderConfirm(orderConfirmReqDTO);
        OrderSubmitReqDTO orderSubmitReqDTO = new OrderSubmitReqDTO();
        orderSubmitReqDTO.setPreOrderNo(orderDTO.getPreOrderNo());
        // 提交订单
        orderDTO = orderSubmit(orderSubmitReqDTO);
        // 创建支付单唤起收银台
        createPay(orderDTO);
        return orderDTO;
    }

    /**
     * 创建支付单
     * @param orderDTO
     */
    private void createPay(OrderDTO orderDTO) {
        PaySuccessRespDTO pay = paymentServiceFacade.createPay(orderDTO);
        orderDTO.setForm(pay.getForm());
        orderDTO.setPayNo(pay.getPayNo());
    }


    private void initOrderDTO(OrderConfirmReqDTO orderConfirmReqDTO) {


    }

    private void checkParam(OrderSubmitReqDTO orderSubmitReqDTO) {
    }

    /**
     * 订单详情
     *
     * @param orderReqDTO
     * @return
     */
    @Override
    public OrderDTO orderInfo(OrderReqDTO orderReqDTO) {
        orderReqDTO.setUserCode(LoginUserContext.getUserCode());
        OrderDO orderDO = orderMapper.selectByOrderNo(orderReqDTO);
        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(orderDO, orderDTO);
        List<OrderGoodsDO> orderGoodsDOS = orderGoodsMapper.listByOrderNos(Collections.singletonList(orderReqDTO.getOrderNo()));
        List<OrderGoodsDTO> orderGoodsDTOList = new ArrayList<>();
        for (OrderGoodsDO orderGoodsDO : orderGoodsDOS) {
            OrderGoodsDTO orderGoodsDTO = new OrderGoodsDTO();
            BeanUtils.copyProperties(orderGoodsDO, orderGoodsDTO);
            orderGoodsDTOList.add(orderGoodsDTO);
        }
        orderDTO.setOrderGoodsDTOList(orderGoodsDTOList);
        orderDTO.setPayStatus(3);
        return orderDTO;
    }

    /**
     * 取消订单
     *
     * @param orderReqDTO
     * @return
     */
    @Override
    public OrderCancelDTO cancelOrder(OrderReqDTO orderReqDTO) {
        return null;
    }

    /**
     * 订单统计
     * @return
     */
    @Override
    public OrderStatisticsDTO orderCount() {
        OrderStatisticsDTO orderStatisticsDTO = new OrderStatisticsDTO();
        List<OrderCount> orderCounts = orderMapper.orderStatistics(LoginUserContext.getUserCode());
        if (!CollectionUtils.isEmpty(orderCounts)) {
            for (OrderCount orderCount : orderCounts) {
                if (OrderStatusEnum.WAIT_PAY.getOrderStatus().equals(orderCount.getOrderStatus())){
                    orderStatisticsDTO.setWaitPayCount(orderCount.getCount());
                }
                if (OrderStatusEnum.WAIT_DELIVERY.getOrderStatus().equals(orderCount.getOrderStatus())){
                    orderStatisticsDTO.setWaitDelivery(orderCount.getCount());
                }
                if (OrderStatusEnum.WAIT_CONFIRM.getOrderStatus().equals(orderCount.getOrderStatus())){
                    orderStatisticsDTO.setWaitConfirm(orderCount.getCount());
                }
                if (OrderStatusEnum.CONFIRMED.getOrderStatus().equals(orderCount.getOrderStatus())){
                    orderStatisticsDTO.setConfirmed(orderCount.getCount());
                }
            }
        }
        return orderStatisticsDTO;
    }

    /**
     * 订单列表
     *
     * @param orderListReqDTO
     * @return
     */
    @Override
    public PageInfo<OrderListDTO> orderList(OrderListReqDTO orderListReqDTO) {
        PageInfo<OrderListDTO> pageInfo = new PageInfo<>();
        List<OrderListDTO> orderListDTOS = new ArrayList<>();
        pageInfo.setpageNo(orderListReqDTO.getPageNo());
        pageInfo.setPageSize(orderListReqDTO.getPageSize());
        orderListReqDTO.setUserCode(LoginUserContext.getUserCode());
        int start = (orderListReqDTO.getPageNo() - 1) * orderListReqDTO.getPageSize();
        int end = orderListReqDTO.getPageSize() * orderListReqDTO.getPageNo() - 1;
        orderListReqDTO.setStart(start);
        orderListReqDTO.setEnd(end);
        // 统计总条数
        int total = orderMapper.countByUserCodeAndStatus(orderListReqDTO);
        if (total <= 0) {
            return pageInfo;
        }
        pageInfo.setTotal(total);
        List<OrderDO> orderDOS = orderMapper.listByUserCodeAndStatus(orderListReqDTO);
        if (!CollectionUtils.isEmpty(orderDOS)) {
            // 批量查询商品订单
            List<String> orderNos = orderDOS.stream().map(OrderDO::getOrderNo).collect(Collectors.toList());
            List<OrderGoodsDO> orderGoodsDOList = orderGoodsMapper.listByOrderNos(orderNos);
            Map<String, List<OrderGoodsDO>> orderGoodsListMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(orderGoodsDOList)) {
                orderGoodsListMap = orderGoodsDOList.stream().collect(Collectors.groupingBy(OrderGoodsDO::getOrderNo));
            }
            for (OrderDO orderDO : orderDOS) {
                try{
                    OrderListDTO orderListDTO = new OrderListDTO();
                    BeanUtils.copyProperties(orderDO, orderListDTO);
                    List<OrderGoodsDO> orderGoodsDOS = orderGoodsListMap.get(orderDO.getOrderNo());
                    if (!CollectionUtils.isEmpty(orderGoodsDOS)) {
                        List<OrderGoodsDTO> orderGoodsDTOList = new ArrayList<>(orderGoodsDOS.size());
                        for (OrderGoodsDO orderGoodsDO : orderGoodsDOS) {
                            OrderGoodsDTO orderGoodsDTO = new OrderGoodsDTO();
                            BeanUtils.copyProperties(orderGoodsDO, orderGoodsDTO);
                            orderGoodsDTOList.add(orderGoodsDTO);
                        }
                        orderListDTO.setGoodsInfo(orderGoodsDTOList.get(0));
                        orderListDTO.setOrderGoodsDTOList(orderGoodsDTOList);
                    }
                    orderListDTO.setOrderStatusStr(OrderStatusEnum.getByOrderStatus(orderDO.getOrderStatus()).getDesc());
                    orderListDTOS.add(orderListDTO);
                }catch (Exception e){
                    log.warn("订单列表异常{}", orderDO.getOrderNo(), e);
                }
            }
            pageInfo.setList(orderListDTOS);
        }
        return pageInfo;
    }
}
